/**
 * Notes: 统一身份认证与权限控制
 * Ver : CCMiniCloud Framework 3.0.0 ALL RIGHTS RESERVED BY cclinux0730 (wechat)
 * Date: 2025-05-01
 */

const appUtil = require('./app_util.js');
const appCode = require('./app_code.js');
const AppError = require('./app_error.js');
const config = require('../../config/config.js');
const UserModel = require('../config/models_config').user_model;
const RouteHelper = require('./route_helper.js');

/**
 * 权限级别定义
 */
const AUTH_LEVEL = {
  NONE: 0,      // 无需身份验证
  USER: 1,      // 需要用户身份
  ADMIN: 2,     // 需要管理员身份
  SUPER: 3      // 需要超级管理员身份
};

/**
 * 权限域定义
 */
const AUTH_DOMAIN = {
  OA: 'oa',      // OA系统权限域
  PLM: 'plm',    // PLM系统权限域
  COMMON: 'common' // 公共权限域
};

/**
 * 跨项目API权限配置
 */
const CROSS_API_AUTH = {
  // OA对外API权限
  'oa_api/user/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/user/list': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/department/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/department/list': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/flow/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/approval/create': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.OA
  },
  'oa_api/health': {
    level: AUTH_LEVEL.NONE,
    domain: AUTH_DOMAIN.OA
  },
  
  // PLM对外API权限
  'plm_api/project/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/project/list': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/research/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/research/list': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/task/info': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/task/list': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/project/update_approval': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.PLM
  },
  'plm_api/health': {
    level: AUTH_LEVEL.NONE,
    domain: AUTH_DOMAIN.PLM
  },
  
  // 公共服务API权限
  'event/publish': {
    level: AUTH_LEVEL.USER,
    domain: AUTH_DOMAIN.COMMON
  },
  'event/process_pending': {
    level: AUTH_LEVEL.ADMIN,
    domain: AUTH_DOMAIN.COMMON
  },
  'health': {
    level: AUTH_LEVEL.NONE,
    domain: AUTH_DOMAIN.COMMON
  }
};

/**
 * 统一身份认证模块
 * 支持跨项目API调用鉴权
 */
class AppAuth {
  /**
   * 跨项目API调用身份认证中间件
   * @param {Object} event 请求事件
   * @returns {Promise<Object>} 认证结果
   */
  static async authMiddleware(event) {
    console.log('[AppAuth] 执行跨项目API认证');
    
    if (!event || !event.route) {
      console.error('[AppAuth] 无效的请求事件');
      throw new AppError('无效的API请求', 401);
    }
    
    const route = event.route;
    const routeInfo = RouteHelper.parseRoute(route);
    
    // 只对跨项目API和系统路由执行认证
    if (!routeInfo.isCrossProjectApi && !routeInfo.isSystemRoute) {
      console.log('[AppAuth] 非跨项目API，跳过认证');
      return { 
        success: true, 
        type: 'none',
        message: '非跨项目API调用'
      };
    }
    
    // 验证API令牌
    const apiToken = event.apiToken || event.token || (event.data && event.data.apiToken);
    
    if (!apiToken) {
      console.error('[AppAuth] 缺少API令牌');
      throw new AppError('API认证失败：缺少令牌', 401);
    }
    
    // 获取请求源项目
    const sourceProject = event.sourceProject || 
                         (event.data && event.data.sourceProject) || 
                         'unknown';
                         
    // 验证项目间调用权限
    const authResult = await this._validateProjectAccess(sourceProject, routeInfo.pid, route);
    
    if (!authResult.success) {
      console.error(`[AppAuth] 跨项目访问拒绝: ${sourceProject} -> ${routeInfo.pid}`);
      throw new AppError(`API认证失败：${authResult.message}`, 403);
    }
    
    console.log(`[AppAuth] 跨项目认证成功: ${sourceProject} -> ${routeInfo.pid}`);
    
    // 返回认证信息，包含源项目和目标项目
    return {
      success: true,
      type: 'cross_project',
      sourceProject,
      targetProject: routeInfo.pid,
      timestamp: Date.now(),
      message: '认证成功'
    };
  }
  
  /**
   * 验证项目间访问权限
   * @param {String} sourceProject 源项目
   * @param {String} targetProject 目标项目
   * @param {String} route 请求路由
   * @returns {Promise<Object>} 验证结果
   */
  static async _validateProjectAccess(sourceProject, targetProject, route) {
    // 系统内部调用直接放行
    if (sourceProject === 'system') {
      return { success: true, message: '系统内部调用' };
    }
    
    // 同项目调用直接放行
    if (sourceProject === targetProject) {
      return { success: true, message: '同项目调用' };
    }
    
    // 基于项目权限矩阵验证访问权限
    // TODO: 从数据库加载项目权限配置
    const accessMatrix = {
      'oa': ['plm', 'system'],  // OA可以访问PLM和System
      'plm': ['oa', 'system'],  // PLM可以访问OA和System
      'system': ['oa', 'plm']   // System可以访问OA和PLM
    };
    
    // 检查是否允许访问
    if (accessMatrix[sourceProject] && 
        accessMatrix[sourceProject].includes(targetProject)) {
      return { success: true, message: '授权访问' };
    }
    
    // 针对特定路由的特殊权限处理
    if (this._hasSpecialRouteAccess(sourceProject, targetProject, route)) {
      return { success: true, message: '特殊路由授权' };
    }
    
    return { 
      success: false, 
      message: `项目 ${sourceProject} 无权访问项目 ${targetProject}` 
    };
  }
  
  /**
   * 检查是否有特定路由的特殊访问权限
   * @param {String} sourceProject 源项目
   * @param {String} targetProject 目标项目
   * @param {String} route 请求路由
   * @returns {Boolean} 是否有特殊访问权限
   */
  static _hasSpecialRouteAccess(sourceProject, targetProject, route) {
    // 特殊路由权限配置
    // 格式: { sourceProject: { targetProject: [allowedRoutes] } }
    const specialRoutes = {
      'oa': {
        'system': ['system/health', 'system/config']
      },
      'plm': {
        'system': ['system/health', 'system/config']
      }
    };
    
    // 检查是否有特殊路由权限
    if (specialRoutes[sourceProject] && 
        specialRoutes[sourceProject][targetProject]) {
      return specialRoutes[sourceProject][targetProject].some(
        r => route.startsWith(r)
      );
    }
    
    return false;
  }
  
  /**
   * 生成跨项目API调用令牌
   * @param {String} sourceProject 源项目
   * @param {String} targetProject 目标项目
   * @returns {Promise<String>} API令牌
   */
  static async generateApiToken(sourceProject, targetProject) {
    // 简单实现，实际应使用更安全的算法
    const timestamp = Date.now();
    const tokenBase = `${sourceProject}_${targetProject}_${timestamp}`;
    const token = this._simpleHash(tokenBase);
    
    console.log(`[AppAuth] 生成API令牌: ${sourceProject} -> ${targetProject}`);
    
    return token;
  }
  
  /**
   * 简单哈希函数（仅用于演示）
   * @param {String} str 输入字符串
   * @returns {String} 哈希值
   */
  static _simpleHash(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // 转换为32位整数
    }
    return Math.abs(hash).toString(16);
  }
}

module.exports = AppAuth; 